#############################
# Describe: 计算某日期N天后的日期
# Date: 20190118
# Author: twostar
#############################

_dayOfMonth = [[0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
                  [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]]


def _check_int(num):
    if isinstance(num, int):
        return num
    if isinstance(num, str) or isinstance(num, float):
        try:
            num = int(num)
            return num
        except:
            return None
    return None


def _check_date(year, month, day):
    year = _check_int(year)
    month = _check_int(month)
    day = _check_int(day)
    if year is None or month is None or day is None:
        return None, None, None
    if not 1 <= year <= 99999:
        # raise TypeError('[x]: year must be in 1...99999')
        return None, None, None
    if not 1 <= month <= 12:
        # raise TypeError('[x]: month must be in 1...12')
        return None, None, None
    if not _isleap(year) and not 1 <= day <= _dayOfMonth[0][month]:
        # raise TypeError('[x]: day must be in 1...%d', _dayOfMonth[0][month])
        return None, None, None
    if _isleap(year) and not 1 <= day <= _dayOfMonth[1][month]:
        # raise TypeError('[x]: day must be in 1...%d', _dayOfMonth[1][month])
        return None, None, None
    return year, month, day


def _isleap(year):
    return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)


def str2date(strdate):
    if not isinstance(strdate, str) or len(strdate.split("/")) != 3:
        return None, None, None
    year, month, day = [_check_int(x) for x in strdate.split("/")]
    return year, month, day

# # 1582/10/5 - 1582/10/14不存在
# def _isRes(year, month, day):
#     if year == 1582 and month == 10 and day >= 5 and day <= 14:
#         return None
#     else:
#         return self


class DateDelta:

    __slots__ =  'year', 'month', 'day'

    def __init__(self, year, month, day):
        year, month, day = _check_date(year, month, day)
        self.year = year
        self.month = month
        self.day = day

    def __str__(self):
        if self.year is None or self.month is None or self.day is None:
            # raise OverflowError("[x]: result out of range")
            return "None"
        return "%d/%d/%d" % (self.year, self.month, self.day)

    def afternday(self, numday):
        if _check_int(numday) is None:
            # raise TypeError('[x]: date delta integer required')
            return "None"
        if self.year is None:
            return "None"
        if numday == 0:
            return self.__str__()

        elif numday > 0:
            while numday > 0:
                # 判定当前年是平年还是闰年
                if _isleap(self.year) is False:
                    loc = 0
                elif _isleap(self.year) is True:
                    loc = 1

                while True:
                    trave = _dayOfMonth[loc][self.month] - self.day
                    if numday <= trave:
                        self.day += numday
                        return self.__str__()
                    else:
                        numday -= trave
                        self.month += 1
                        self.day = 0
                        if self.month == 13:
                            self.month = 1
                            self.day = 0
                            self.year += 1
                            break
            return self.__str__()

        elif numday < 0:
            while numday < 0:
                if _isleap(self.year) is False:
                    loc = 0
                elif _isleap(self.year) is True:
                    loc = 1

                while True:
                    if 0 - numday < self.day:
                        self.day += numday
                        return self.__str__()
                    else:
                        numday += self.day
                        self.month -= 1
                        self.day = _dayOfMonth[loc][self.month]
                        if self.month == 0:
                            self.month = 12
                            self.day = _dayOfMonth[loc][self.month]
                            self.year -= 1
                            break
            return self.__str__()


DateDelta.min = DateDelta(1, 1, 1)
DateDelta.max = DateDelta(99999, 12, 31)


if __name__ == '__main__':
    pass

    # year, month, day = str2date("2018/12/20")
    # mydate = DateDelta(year, month, day)
    # print(mydate.afternday(3))
    # print(mydate.afternday(-2))
    # print(mydate.afternday(30))

    # mydate1 =  DateDelta(1, 1, 1)
    # print(mydate1 - 5)
